热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

表里|也就是_UE4Unlua源码解析7Lua通过UE命名空间访问C++类型的实现原理

篇首语:本文由编程笔记#小编为大家整理,主要介绍了UE4Unlua源码解析7-Lua通过UE命名空间访问C++类型的实现原理相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了UE4 Unlua源码解析7 - Lua通过UE命名空间访问C++类型的实现原理相关的知识,希望对你有一定的参考价值。



Lua通过UE命名空间访问C++类型的实现原理


          • 1.1 UE4发生了 什么
          • 1.2 UE4.UKismetSystemLibrary发生了什么
          • 1.3 UE4.UKismetSystemLibrary.PrintString发生了什么
          • 1.4 UE4.UKismetSystemLibrary.PrintString(“Hello”)发生了什么






举例 UE4.UKismetSystemLibrary.PrintString(“hello”)

我们来看Unlua提供的例子的HelloWorld

代码是

local hello = “HelloWorld”
UE4.UKismetSystemLibrary.PrintString(hello)

这个例子我们最终会调到UE4的方法,并且成功执行,那么首先,我们要解答的问题就是为什么Lua这么写最终能调用到C++的方法,

而且Lua传的参数是Lua的字符串,为什么C++能成功执行,这简单的代码,背后到底做了什么事情


1.1 UE4发生了 什么

Unlua.lua中声明了UE4,可以看到UE4其实就是全局表_G,而且他的元表是global_mt,Index元方法为global_index,我们去看看global_index

第73行拿到传入的索引k,检查第一个字母是不是UE的类的首字母,是就调用RegisterClass,如果是E,就调用RegisterEnum,然后调用rawget,rawget方法是不使用Index元方法的取值函数,可以猜测上面的函数执行完之后,t表也就是UE4表里已经就有了索引k的值了。

具体的执行逻辑接着看


1.2 UE4.UKismetSystemLibrary发生了什么

由上节讲到的,UE4.UKismetSystemLibrary的时候,因为UE4是表,所以就去表里找UKismetSystemLibrary,但是第一次肯定是找不到的,于是走到UE4的元表的元方法Index,也就是执行global_index,传进来的t是UE4,k是“UKismetSystemLibrary”

由之前的分析可以看到代码会走到RegisterClass,然后传入k

RegisterClass在lua测的声明如下

看到LuaContext.cpp里

lua api lua_register前面讲到了,将C函数f设置为全局名称name的新值,lua端可以通过name调用C方法f

所以这行代码将C函数Global_RegisterClass注册,在Lua端通过Lua全局名称RegisterClass调用

Global_RegisterClass和RegisterClass逐行解释之前讲过了,此处只说结果

Global_RegisterClass 读虚拟栈的大小,当小于1的时候返回,否则调用RegisterClass,参数传(虚拟机,栈底的值转成C 的string)



此时虚拟栈的内容是传进来类名“UKismetSystemLibrary”,以及参数的数量1,所以传递给RegisterClass的参数是(虚拟机L,“UKismetSystemLibrary”)


RegisterClass逐行解释之前讲过了,总之是两大部分

1 根据UE4反射生成UClass的描述信息FClassDesc ,然后存储到UnLua的存储全局反射数据的GReflectionRegistry对象中。

2 根据生成的FClassDesc 为其在Lua中注册table,然后设置table的元表为自己,然后往table里塞一些元方法

RegisterClass结束后,UE4.UKismetSystemLibrary就是一个Lua端的表了,这个表的元表是自己,并且元方法Index是LuaCore中的方法Class_Index

类图如下


1.3 UE4.UKismetSystemLibrary.PrintString发生了什么

截至目前,UE4.UKismetSystemLibrary就能拿到上一步生成的Lua table了,此时调用.PrintString的时候,可以看到表里没用这个数据,所以走到元表的Index元方法,之前我们知道,元方法为LuaCore中的Class_Index,所以重点看这个方法即可

其中最重要的是走到GetField

GetField和RegiestClass很像,就像是注册类一样,GetField主要也做两件事

1

​ 如果传进来的是属性,就根据UE4反射生成FPropertyDesc

​ 如果传进来的是方法,就根据UE4反射生成FFunctionDesc,并且把FPropertyDesc或FFunctionDesc存在FClassDesc中

2

​ 如果是属性 就在表里存FPropertyDesc,然后将FPropertyDesc压栈,作为返回值返回

​ 如果是方法,就在表里存FFunctionDesc+C方法Class_CallUFunction的闭包进去,FFunctionDesc作为Upvalue。然后将FFunctionDesc+C方法Class_CallUFunction的闭包压栈,作为返回值返回

此时的类图如下


1.4 UE4.UKismetSystemLibrary.PrintString(“Hello”)发生了什么

截至目前,相当于调用LuaCore的Class_CallUFunction

传进来的参数是lua的string hello

根据之前的解释C++通过闭包里的FFunctionDesc执行方法CallUE,参数是Lua传进去的,通过

1)执行PreCall,根据【UFunctionDesc】和Lua参数,将Lua参数转换成C++参数,再根据【UFunctionDesc】反射信息,将C++参数写入到一个缓存区中

2)执行 UObject::ProcessEvent(FinalFunction, Params),参数FinalFunction是UFunction,参数Params是前面保存有C++参数的缓存区。ProcessEvent执行时,即调用了真正我们想调用的C++ Create函数,然后把C++返回值放入了Params缓存区中

3)执行PostCall,从Params缓存区中读出C++返回值,转换成Lua返回值,Push进Lua栈,返回给Lua。

结束,至此,屏幕应该输出Hello


推荐阅读
  • Web动态服务器Python基本实现
    Web动态服务器Python基本实现 ... [详细]
  • OBS Studio自动化实践:利用脚本批量生成录制场景
    本文探讨了如何利用OBS Studio进行高效录屏,并通过脚本实现场景的自动生成。适合对自动化办公感兴趣的读者。 ... [详细]
  • 函子(Functor)是函数式编程中的一个重要概念,它不仅是一个特殊的容器,还提供了一种优雅的方式来处理值和函数。本文将详细介绍函子的基本概念及其在函数式编程中的应用,包括如何通过函子控制副作用、处理异常以及进行异步操作。 ... [详细]
  • 长期从事ABAP开发工作的专业人士,在面对行业新趋势时,往往需要重新审视自己的发展方向。本文探讨了几位资深专家对ABAP未来走向的看法,以及开发者应如何调整技能以适应新的技术环境。 ... [详细]
  • 本文详细介绍了如何在Oracle VM VirtualBox中实现主机与虚拟机之间的数据交换,包括安装Guest Additions增强功能,以及如何利用这些功能进行文件传输、屏幕调整等操作。 ... [详细]
  • 本文介绍了如何通过C#语言调用动态链接库(DLL)中的函数来实现IC卡的基本操作,包括初始化设备、设置密码模式、获取设备状态等,并详细展示了将TextBox中的数据写入IC卡的具体实现方法。 ... [详细]
  • spring boot使用jetty无法启动 ... [详细]
  • 入门指南:使用FastRPC技术连接Qualcomm Hexagon DSP
    本文旨在为初学者提供关于如何使用FastRPC技术连接Qualcomm Hexagon DSP的基础知识。FastRPC技术允许开发者在本地客户端实现远程调用,从而简化Hexagon DSP的开发和调试过程。 ... [详细]
  • Docker安全策略与管理
    本文探讨了Docker的安全挑战、核心安全特性及其管理策略,旨在帮助读者深入理解Docker安全机制,并提供实用的安全管理建议。 ... [详细]
  • 对于初学者而言,搭建一个高效稳定的 Python 开发环境是入门的关键一步。本文将详细介绍如何利用 Anaconda 和 Jupyter Notebook 来构建一个既易于管理又功能强大的开发环境。 ... [详细]
  • 本文探讨了如何通过优化 DOM 操作来提升 JavaScript 的性能,包括使用 `createElement` 函数、动画元素、理解重绘事件及处理鼠标滚动事件等关键主题。 ... [详细]
  • 本文详细介绍了JQuery Mobile框架中特有的事件和方法,帮助开发者更好地理解和应用这些特性,提升移动Web开发的效率。 ... [详细]
  • Requests库的基本使用方法
    本文介绍了Python中Requests库的基础用法,包括如何安装、GET和POST请求的实现、如何处理Cookies和Headers,以及如何解析JSON响应。相比urllib库,Requests库提供了更为简洁高效的接口来处理HTTP请求。 ... [详细]
  • 问题场景用Java进行web开发过程当中,当遇到很多很多个字段的实体时,最苦恼的莫过于编辑字段的查看和修改界面,发现2个页面存在很多重复信息,能不能写一遍?有没有轮子用都不如自己造。解决方式笔者根据自 ... [详细]
  • 分层学习率衰减在NLP预训练模型中的应用
    本文探讨了如何通过分层学习率衰减技术来优化NLP预训练模型的微调过程,特别是针对BERT模型。通过调整不同层的学习率,可以有效提高模型性能。 ... [详细]
author-avatar
鄙人fisher_779
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有